package com.tp.base;

import java.math.BigDecimal;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import com.jfinal.log.Log;
import com.jfinal.plugin.activerecord.ActiveRecordException;
import com.jfinal.plugin.activerecord.Config;
import com.jfinal.plugin.activerecord.Db;
import com.jfinal.plugin.activerecord.Model;
import com.jfinal.plugin.activerecord.Page;
import com.jfinal.plugin.activerecord.Table;
import com.jfinal.plugin.activerecord.TableMapping;
import com.tp.utils.DateUtils;
import com.tp.utils.NumberUtils;

/**
 * Model 优化修改
 * 
 * @param <M>
 */
public class BaseModel<M extends Model<M>> extends Model<M> {

	protected static final long serialVersionUID = 1L;

	protected static final Log log = Log.getLog(BaseModel.class);

	public static final Integer TYPE_MODEL = 1; //数据
	public static final Integer TYPE_SYSTEM = 2; //系统

	public static final String MODEL_SAVE = "添加";
	public static final String MODEL_UPDATE = "更新";
	public static final String MODEL_DELETE = "删除";
	public static final String SYSTEM_LOGIN = "登入";
	public static final String SYSTEM_LOGOUT = "登出";

	@Override
	public Integer getInt(String attr) {
		Object obj = get(attr);
		if (obj == null) {
			return null;
		} else if (obj instanceof Integer) {
			return (Integer) obj;
		} else if (obj instanceof BigDecimal) {
			return ((BigDecimal) obj).intValue();
		} else if (obj instanceof String) {
			try {
				return Integer.parseInt((String) obj);
			} catch (Exception e) {
				throw new RuntimeException("String can not cast to Integer : " + attr.toString());
			}
		} else {
			try {
				return Integer.parseInt(obj.toString());
			} catch (Exception e) {
				throw new RuntimeException("Object can not cast to Integer : " + attr.toString());
			}
		}
	}

	public Table getTable() {
		return TableMapping.me().getTable(getClass());
	}

	/****************************************** 加入公共日志 ******************************************/
	@Override
	public boolean save() {
		boolean flag = super.save();
		String tableName = getTable().getName();
		String[] keys = getTable().getPrimaryKey();
		Object id = null;
		if (keys != null && keys.length >= 1) {
			id = get(keys[0]);
		}
		Integer primaryId = (id != null) ? NumberUtils.parseInt(id) : null;
		saveLog(tableName, primaryId, MODEL_SAVE);
		return flag;
	}

	@Override
	public boolean delete() {
		boolean flag = super.delete();
		String tableName = getTable().getName();
		String[] keys = getTable().getPrimaryKey();
		Object id = null;
		if (keys != null && keys.length >= 1) {
			id = get(keys[0]);
		}
		Integer primaryId = (id != null) ? NumberUtils.parseInt(id) : null;
		saveLog(tableName, primaryId, MODEL_DELETE);
		return flag;
	}

	@Override
	public boolean deleteById(Object id) {
		boolean flag = super.deleteById(id);
		String tableName = getTable().getName();
		Integer primaryId = (id != null) ? NumberUtils.parseInt(id) : null;
		saveLog(tableName, primaryId, MODEL_DELETE);
		return flag;
	}

	@Override
	public boolean update() {
		boolean flag = super.update();
		String tableName = getTable().getName();
		String[] keys = getTable().getPrimaryKey();
		Object id = null;
		if (keys != null && keys.length >= 1) {
			id = get(keys[0]);
		}
		Integer primaryId = (id != null) ? NumberUtils.parseInt(id) : null;
		saveLog(tableName, primaryId, MODEL_UPDATE);
		return flag;
	}

	protected void saveLog(String tableName, Integer primaryId, String operType) {
		try {
			Integer updateId = getAttrs().containsKey("update_id") ? getInt("update_id") : 0;
			String updateTime = getAttrs().containsKey("update_time") ? getStr("update_time") : DateUtils.getNow(DateUtils.DEFAULT_REGEX_YYYY_MM_DD_HH_MIN_SS);
			String sql = "INSERT INTO `sys_log` ( `log_type`, `oper_object`, `oper_table`," 
					+ " `oper_id`, `oper_type`, `oper_remark`, `create_time`, `create_id`) " 
					+ "VALUES (?, ?, ?, ?, ?, ?, ?, ?)";
			Db.update(sql, TYPE_MODEL, tableName, tableName, primaryId, operType, "", updateTime, updateId);
		} catch (Exception e) {
			log.error("添加日志失败", e);
		}
	}

	/**
	 * 重写分页 解决 当前页数 大于 总页数时 的bug
	 *
	 * @param paginator       the page
	 * @param select          the select part of the sql statement
	 * @param sqlExceptSelect the sql statement excluded select part
	 * @param paras           the parameters of sql
	 * @return
	 */
	@SuppressWarnings({ "rawtypes", "unused" })
	public Page<M> paginate(Paginator paginator, String select, String sqlExceptSelect, Object... paras) {
		Config config = _getConfig();

		int pageNumber = paginator.getPageNo();
		int pageSize = paginator.getPageSize();

		if (pageNumber < 1 || pageSize < 1) {
			throw new ActiveRecordException("pageNumber and pageSize must more than 0");
		}
		
		String totalRowSql = "select count(*) " + config.getDialect().replaceOrderBy(sqlExceptSelect);
		List result = Db.query(totalRowSql, paras);
		int size = result.size();

		long totalRow;
		if (false) {
			totalRow = size;
		} else {
			totalRow = (size > 0) ? ((Number) result.get(0)).longValue() : 0;
		}

		if (totalRow == 0) {
			// totalRow = 0;
			return new Page<M>(new ArrayList<M>(0), pageNumber, pageSize, 0, 0);
		}

		int totalPage = (int) (totalRow / pageSize);
		if (totalRow % pageSize != 0) {
			totalPage++;
		}

		if (pageNumber > totalPage) {
			//return new Page<M>(new ArrayList<M>(0), pageNumber, pageSize, totalPage, (int)totalRow);
			//当前页数 大于总页数的时候 把当前页设置为第1页
			pageNumber = 1;
		}
		//升级到jfinal 3.5
		StringBuilder ret = new StringBuilder();
		ret.append(select).append(" ").append(sqlExceptSelect);
		String sql = config.getDialect().forPaginate(pageNumber, pageSize, ret);
		List<M> list = super.find(sql, paras);
		return new Page<M>(list, pageNumber, pageSize, totalPage, (int) totalRow);
	}

	/**
	 * Find model.
	 * 
	 * @param where
	 *            an SQL statement that may contain one or more '?' IN parameter
	 *            placeholders
	 * @param paras
	 *            the parameters of sql
	 * @return the list of Model
	 */
	public List<M> findByWhere(String where, Object... paras) {
		return findByWhereAndColumns(where, "*", paras);
	}

	/**
	 * Find model.
	 * 
	 * @param where
	 *            an SQL statement that may contain one or more '?' IN parameter
	 *            placeholders
	 * @param columns
	 * @param paras
	 *            the parameters of sql
	 * @return the list of Model
	 */
	public List<M> findByWhereAndColumns(String where, String columns, Object... paras) {
		String sql = " select " + columns + " from " + getTable().getName() + " " + where;
		return find(sql, paras);
	}

	/**
	 * Find first model. I recommend add "limit 1" in your sql.
	 * 
	 * @param where
	 *            an SQL statement that may contain one or more '?' IN parameter
	 *            placeholders
	 * @param paras
	 *            the parameters of sql
	 * @return Model
	 */
	public M findFirstByWhere(String where, Object... paras) {
		return findFirstByWhereAndColumns(where, "*", paras);
	}

	/**
	 * Find first model. I recommend add "limit 1" in your sql.
	 * 
	 * @param where
	 *            an SQL statement that may contain one or more '?' IN parameter
	 *            placeholders
	 * @param columns
	 * @param paras
	 *            the parameters of sql
	 * @return Model
	 */
	public M findFirstByWhereAndColumns(String where, String columns, Object... paras) {
		String sql = " select " + columns + " from " + getTable().getName() + " " + where;
		return findFirst(sql, paras);
	}

	// ///////////////////////////////////////缓存部分/////////////////////////////////////////////////

//	/**
//	 * paginateCache是重构版paginateByCache，使用自己的Cache
//	 * 
//	 * 2015年5月7日 下午12:20:23 flyfox 330627517@qq.com
//	 * 
//	 * @param cacheName
//	 * @param key
//	 * @param paginator
//	 * @param select
//	 * @param sqlExceptSelect
//	 * @param paras
//	 * @return
//	 */
//	public Page<M> paginateCache(String cacheName, String key, Paginator paginator, String select,
//			String sqlExceptSelect, Object... paras) {
//		Cache cache = CacheManager.get(cacheName);
//		Page<M> result = cache.get(key);
//		if (result == null) {
//			result = paginate(paginator.getPageNo(), paginator.getPageSize(), select, sqlExceptSelect, paras);
//			cache.add(key, result);
//		}
//		return result;
//	}
//
//	/**
//	 * findCache是重构版findByCache，使用自己的Cache
//	 * 
//	 * 2015年5月7日 下午12:12:08 flyfox 330627517@qq.com
//	 * 
//	 * @param cacheName
//	 * @param key
//	 * @param sql
//	 * @param paras
//	 * @return
//	 */
//	public List<M> findCache(String cacheName, String key, String sql, Object... paras) {
//		Cache cache = CacheManager.get(cacheName);
//		List<M> result = cache.get(key);
//		if (result == null) {
//			result = find(sql, paras);
//			cache.add(key, result);
//		}
//		return result;
//	}
//
//	/**
//	 * findFirstCache是重构版findByCache，使用自己的Cache
//	 * 
//	 * 2015年5月7日 下午12:12:08 flyfox 330627517@qq.com
//	 * 
//	 * @param cacheName
//	 * @param key
//	 * @param sql
//	 * @param paras
//	 * @return
//	 */
//	public M findFirstCache(String cacheName, String key, String sql, Object... paras) {
//		Cache cache = CacheManager.get(cacheName);
//		M result = cache.get(key);
//		if (result == null) {
//			result = findFirst(sql, paras);
//			cache.add(key, result);
//		}
//		return result;
//	}
//
//	/**
//	 * 根据Key删除Cache
//	 * 
//	 * 2015年5月7日 下午12:16:43 flyfox 330627517@qq.com
//	 * 
//	 * @param cacheName
//	 * @param key
//	 */
//	public void removeCache(String cacheName, String key) {
//		Cache cache = CacheManager.get(cacheName);
//		cache.remove(key);
//	}
//
//	/**
//	 * 清理Cache所有数据
//	 * 
//	 * 2015年5月7日 下午12:16:52 flyfox 330627517@qq.com
//	 * 
//	 * @param cacheName
//	 */
//	public void clearCache(String cacheName) {
//		Cache cache = CacheManager.get(cacheName);
//		cache.clear();
//	}

	public Map<String, Object> getAttrs() {
		return super._getAttrs();
	}

	public Object[] getAttrValues() {
		return super._getAttrValues();
	}

}
